/**
 *  memory control util for windows
 *  @author hrz
 */
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <stdbool.h>

#define  UNIT_MB 1048576
#define DEFAULT_MEMORY_BLOCK_SIZE 10485760
#define DEFAULT_BLOCK_ARRAY_LENGTH 10240
int firstLoad = 0;
int desPercent = 0;
int *ptrBlockArray[DEFAULT_BLOCK_ARRAY_LENGTH] = {NULL};
DWORD REFRESH_HZ_UNIT = 1000;

int needExit = 0;
int refresh_hz = 0;
struct MemInfo {
    unsigned long long total;
    unsigned long long free;
};


int main(int argc, char *argv[], char *envp[]) {
    initPercent();
    initRate();
    printf("###########Starting... please wait #################\n");
    struct MemInfo memInfo = {0, 0};
    while (needExit == 0) {
        initMemoryInfo(&memInfo);
        changeUsedMemory(&memInfo);
        Sleep(refresh_hz);
    }
    return 0;
}


/**
 * 输入 期望内存占比 范围(10,80)
 * @return percent 合法输入
 */
void initPercent() {
    printf("input memory percent ,in scope (10,90)\n");
    int iPercent;
    scanf("%d", &iPercent);
    printf("OK.Input finished\n");
    printf("using percent:%d\n", iPercent);
    if (iPercent < 10 || iPercent > 80) {
        printf("invalid value , system exit");
        exit(0);
    }
    desPercent = iPercent;
}

void initRate() {
    printf("input rate (5,100)\n");
    int iRate;
    scanf("%d", &iRate);
    printf("OK.Input finished\n");
    printf("using rate:%d\n", iRate);
    if (iRate < 6 || iRate > 99) {
        printf("invalid value, the  is  rate not in range (5,100) , system exit");
        exit(0);
    }
    refresh_hz = iRate * REFRESH_HZ_UNIT;
}

void initMemoryInfo(struct MemInfo *memInfo) {
    MEMORYSTATUSEX statusex;
    statusex.dwLength = sizeof(statusex);
    if (GlobalMemoryStatusEx(&statusex)) {
        memInfo->free = statusex.ullAvailPhys / UNIT_MB;
        memInfo->total = statusex.ullTotalPhys / UNIT_MB;
        printf("current memory info->total %lld MB (%lld MB available)\n", memInfo->total, memInfo->free);
    } else {
        printf("can not get memory info, system exit\n");
        exit(0);
    }
}


void changeUsedMemory(struct MemInfo *memInfo) {
    printf("begin refresh memory blocks  \n");
    unsigned long long usedPercent = (unsigned long long) (((memInfo->total - memInfo->free) * 1.0 / memInfo->total) *
                                                           100);
    if (usedPercent > desPercent) {
        //如果没有需要释放的内存则跳过
        if (firstLoad == 0) {
            firstLoad = 1;
            printf("current memory is %d is grater than  the destination percent %d,do nothing\n", usedPercent, desPercent);
            return;
        }
        freeMemoryBlock(memInfo);
        //释放内存
        return;
    }
    addMemoryBlock(memInfo);
    //申请内存
    printf("end refresh memory blocks  \n");
}


void freeMemoryBlock(struct MemInfo *memInfo) {
    printf("begin free memory blocks\n");
    unsigned long long dist = (unsigned long long) (memInfo->total * desPercent * 0.01);
    //计算需要释放的块 = 当前占用 - 目标占用 = （总内存 - 可用内存) - 目标占用内存
    unsigned long long needToFreeBlockCount = ((memInfo->total - memInfo->free - dist)) / 10;
    printf("need to free blocks: %lld\n", needToFreeBlockCount);
    if (needToFreeBlockCount < 0) {
        printf("end free memory blocks with exception \n");
        return;
    }
    long freeCount = 0;
    for (int i = 0; i < DEFAULT_BLOCK_ARRAY_LENGTH; i++) {
        if (needToFreeBlockCount < 1) {
            break;
        }
        if (ptrBlockArray[i] != NULL) {
            //指向默认指针
            free(ptrBlockArray[i]);
            ptrBlockArray[i] = NULL;
            needToFreeBlockCount = needToFreeBlockCount - 1;
            freeCount = freeCount + 1;
        }
    }
    printf("finally  %ld blocks\n had been free", freeCount);
}


void addMemoryBlock(struct MemInfo *memInfo) {
    printf("begin add memory blocks\n");
    //计算 需要增加的内存 = 目标占用内存 - 已经占用内存 = 目标占用内存 -（总内存-可用内存）
    unsigned long long needToAddBlockCount = (unsigned long long)
            ((memInfo->total * desPercent * 0.01 - memInfo->total + memInfo->free) / 10);
    printf("need to add blocks: %lld\n", needToAddBlockCount);
    if (needToAddBlockCount < 0) {
        printf("end add memory blocks with exception \n");
        return;
    }
    long added = 0;
    for (int i = 0; i < DEFAULT_BLOCK_ARRAY_LENGTH; i++) {
        //分配内存数组
        if (needToAddBlockCount < 1) {
            break;
        }
        //指向默认，则是未分配状态
        if (ptrBlockArray[i] == NULL) {
            ptrBlockArray[i] = (int *) malloc(DEFAULT_MEMORY_BLOCK_SIZE);
            if (ptrBlockArray[i] == NULL) {
                //没有可分配内存，退出
                break;
            }
            memset(ptrBlockArray[i], 0, DEFAULT_MEMORY_BLOCK_SIZE);
            needToAddBlockCount = needToAddBlockCount - 1;
            added = added + 1;
        }
    }
    printf("finally %ld blocks had been added\n", added);
}

